package com.lg.distributed.transaction.message.aop;

import com.lg.distributed.transaction.message.annotation.LgDistributedTransaction;
import com.lg.distributed.transaction.message.constant.MQConstants;
import com.lg.distributed.transaction.message.coordinator.DBCoordinator;
import com.lg.distributed.transaction.message.model.MessageEntity;
import com.lg.distributed.transaction.message.model.RabbitMetaMessage;
import com.lg.distributed.transaction.message.sender.RabbitSender;
import com.lg.distributed.transaction.message.util.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * aop 拦截 注解，实现动态增强第一步
 *
 * @author by Mr. Li 2020/12/11 22:19
 */
@Component
@Aspect
@Slf4j
public class TransactionSender {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private RabbitSender rabbitSender;

    /**
     * 雪花算法生成全局唯一id
     */
    @Autowired
    private IdWorker idWorker;

    @Autowired
    @Qualifier("delayQueue")
    private Queue queue;

    /**
     * 切点
     */
    @Pointcut("@annotation(com.lg.distributed.transaction.message.annotation.LgDistributedTransaction)")
    public void pointCut() {
    }

    /**
     * 环绕
     * 这里是将生成的 bizName 作为唯一id
     *
     * @param joinPoint
     * @param rd
     */
    @Around("pointCut() && @annotation(rd)")
    public void sendMsg(ProceedingJoinPoint joinPoint, LgDistributedTransaction rd) throws Throwable {
        log.info("==> custom mq annotation,rd:{}", rd);
        String exchange = rd.exchange();
        String routingKey = rd.routingKey();
        String bizName = rd.bizName() + MQConstants.DB_SPLIT + getCurrentDateTime();
        String dbCoordinator = rd.dbCoordinator();
        String msgId = idWorker.nextId() + MQConstants.DB_SPLIT + getCurrentDateTime();
        if (queue.getArguments() == null) {
            // 填充 死信队列 信息
            /**
             * 需要设置三个设置
             * x-dead-letter-exchange:order-event-exchange
             * x-dead-letter-routing-key:order.release.order
             * x-message-ttl:60000
             *
             * 给当前队列绑定一个交换机，设置一个路由键，设置一个过期时间
             *
             */
            queue.addArgument("x-dead-letter-exchange", exchange);
            queue.addArgument("x-dead-letter-exchange", routingKey);
            queue.addArgument("x-message-ttl", 60000);
        }

        DBCoordinator coordinator = null;
        // 将获取到的信息持久化到磁盘
        try {
            coordinator = (DBCoordinator) applicationContext.getBean(dbCoordinator);
        } catch (Exception e) {
            log.error("无消息存储类，事务执行终止");
            return;
        }
        // 发送消息前，先持久化消息
        coordinator.setMsgPrepare(msgId);
        // 放行
        Object proceed = null;
        try {
            proceed = joinPoint.proceed();
        } catch (Exception e) {
            log.error("业务执行失败，业务名称：{}", bizName);
            throw e;
        }

        if (proceed == null) {
            proceed = MQConstants.BLANK_STR;
        }
        // 发送信息
        RabbitMetaMessage rabbitMetaMessage = new RabbitMetaMessage();
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setClassType(joinPoint.getSignature().getDeclaringTypeName());
        messageEntity.setMessageId(msgId);
        messageEntity.setContent(bizName);
        messageEntity.setCreateTime(new Date());
        messageEntity.setMessageStatus(0);
        messageEntity.setRoutingKey(routingKey);
        messageEntity.setToExchange(exchange);
        rabbitMetaMessage.setMessageEntity(messageEntity);
        rabbitMetaMessage.setPayload(proceed);

        // 将消息设置为ready状态
        coordinator.setMsgReady(msgId, rabbitMetaMessage);

        //发送
        try {
            rabbitSender.setCorrelationData(dbCoordinator);
            rabbitSender.send(rabbitMetaMessage);
        } catch (Exception e) {
            log.error("第一阶段消息发送异常" + bizName + e);
            throw e;
        }

    }

    private static String getCurrentDateTime() {
        SimpleDateFormat df = new SimpleDateFormat(MQConstants.TIME_PATTERN);
        return df.format(new Date());
    }

}
